package main

import (
	"fmt"
	"log"
	"sync"
	"time"
)

/**
 * @Classname p2
 * @Description TODO
 * @author cjf
 * @Date 2021/7/14 16:58
 * @Version V1.0
 */

/*
# 困难的
- interface
- map
- 发布系统，能发布k8s node(jtype字段) 不同的类型的任务
- 增量更新：开启新的，停掉旧的
- 原有的是a,b,c ，b,c,d --> 开启d, 停掉a

*/

type deployJob interface {
	start()

	stop()

	hash() string
}

type k8sD struct {
	Id    int
	Name  string
	k8sNs string
}

type hostD struct {
	Id     int
	Name   string
	HostIp string
}

func (kd *k8sD) start() {
	log.Printf("[host.deploy.start][%v]", kd)
}

func (kd *k8sD) stop() {
	log.Printf("[host.deploy.stop][%v]", kd)
}

func (kd *k8sD) hash() string {
	return kd.Name
}

func (hd *hostD) start() {
	log.Printf("[host.deploy.start][%v]", hd)
}

func (hd *hostD) stop() {
	log.Printf("[host.deploy.stop][%v]", hd)
}

func (hd *hostD) hash() string {
	return hd.Name
}

type jobManager struct {
	targetMtx     sync.RWMutex
	activeTargets map[string]deployJob
}

func (jm *jobManager) sync(jobs []deployJob) {

	// 增量更新体现就是 新的新增，旧的删除
	// 在jobs里面 不在	activeTargets 说明 新增
	// 在jobs里面 也在	activeTargets 说明 不动
	// 不在jobs里面 在	activeTargets 说明 删除

	thisAll := make(map[string]deployJob)
	thisNew := make(map[string]deployJob)

	//加锁
	jm.targetMtx.Lock()

	//all 和 new
	for _, t := range jobs {

		//计算hash并保存在activeTargets
		hash := t.hash()
		thisAll[hash] = t
		if _, loaded := jm.activeTargets[hash]; !loaded {
			thisNew[hash] = t
			jm.activeTargets[hash] = t
		}
	}

	//whether old
	for hash, t := range jm.activeTargets {
		if _, loaded := thisAll[hash]; !loaded {

			//stop old job
			t.stop()
			//update map
			delete(jm.activeTargets, hash)

		}
	}

	jm.targetMtx.Unlock()

	// start new
	for _, t := range thisNew {
		t.start()
	}
}

func main() {
	jm := &jobManager{
		activeTargets: make(map[string]deployJob),
	}

	//初始化
	cjs := make([]deployJob, 0)

	//add 3 k8s job
	for i := 0; i < 3; i++ {
		name := fmt.Sprintf("k8s_job_%d", i)
		ns := fmt.Sprintf("namespace_%d", i)
		cj := k8sD{
			Id:    i,
			Name:  name,
			k8sNs: ns,
		}
		cjs = append(cjs, &cj)

	}
	// add 3 host job
	for i := 0; i < 3; i++ {
		name := fmt.Sprintf("host_job_%d", i)
		ip := fmt.Sprintf("1.1.1.%d", i)
		cj := hostD{
			Id:     i,
			Name:   name,
			HostIp: ip,
		}
		cjs = append(cjs, &cj)
	}

	log.Printf("[第一轮分配][分配6个任务：3个k8s 3个host]")
	jm.sync(cjs)
	time.Sleep(5 * time.Second)

	cjs = make([]deployJob, 0)
	// add 2 k8sjob
	for i := 1; i < 3; i++ {
		name := fmt.Sprintf("k8s_job_%d", i)
		ns := fmt.Sprintf("namespace_%d", i)
		cj := k8sD{
			Id:    i,
			Name:  name,
			k8sNs: ns,
		}
		cjs = append(cjs, &cj)
	}
	log.Printf("[第二轮分配][分配2个任务：2个k8s ]")
	jm.sync(cjs)
	time.Sleep(5 * time.Second)

	cjs = make([]deployJob, 0)
	// add 5 host job
	for i := 1; i < 7; i++ {
		name := fmt.Sprintf("host_job_%d", i)
		ip := fmt.Sprintf("1.1.1.%d", i)
		cj := hostD{
			Id:     i,
			Name:   name,
			HostIp: ip,
		}
		cjs = append(cjs, &cj)
	}

	log.Printf("[第三轮分配][分配6个任务：6个host]")
	jm.sync(cjs)
	time.Sleep(5 * time.Second)

	cjs = make([]deployJob, 0)
	// add 2 k8sjob
	for i := 1; i < 6; i++ {
		name := fmt.Sprintf("k8s_job_%d", i)
		ns := fmt.Sprintf("namespace_%d", i)
		cj := k8sD{
			Id:    i,
			Name:  name,
			k8sNs: ns,
		}
		cjs = append(cjs, &cj)
	}
	log.Printf("[第四轮分配][分配5个任务：5个k8s ]")
	jm.sync(cjs)
	time.Sleep(5 * time.Second)
}
